import ure as re
import usocket as socket
try:
    import ussl
    SUPPORT_SSL = True
except ImportError:
    ussl = None
    SUPPORT_SSL = False


def make_form_urlencoded_data(payload):
    # TODO : urlencode the value
    if type(payload) is dict:
        return '&'.join(['%s=%s' % (key, value) for key, value in payload.items()])
    return ''


status_code_regex = re.compile(r'^HTTP\/1\.1\s(\d+)')
header_regex = re.compile(r'^(.*)\:\s(.*)')


class HttpClient:

    def __init__(self, url):
        proto, host, port, path = urlparse(url)
        self.proto = proto
        self.host = host
        self.port = port
        self.path = path

    def do_request(self, method='GET', payload=None):
        proto = self.proto
        host = self.host
        port = self.port
        path = self.path

        sock = socket.socket()
        addr = socket.getaddrinfo(host, port)[0][-1]
        print('Connecting to: %s' % str(addr))
        sock.connect(addr)
        if proto == 'https:':
            assert SUPPORT_SSL, 'HTTPS not supported: could not find ussl'
            sock = ussl.wrap_socket(sock)
        stream = sock.makefile('rwb', 0)

        def writeln(msg):
            print('Sending: %s' % msg)
            stream.write(bytes('%s\r\n' % (msg), 'utf-8'))

        writeln('%s %s HTTP/1.1' % (method, path))
        host_string = host if port == 80 else '%s:%s' % (host, port)
        writeln('%s: %s' % ('Host', host_string))
        writeln('User-Agent: deohttp')
        writeln('Accept: */*')
        if method == 'POST':
            print(payload)
            if payload:
                writeln('Content-Type: application/x-www-form-urlencoded')
                data = make_form_urlencoded_data(payload)
                _bytes_ = bytes(data, 'utf-8')
                writeln('Content-Length: %s' % len(_bytes_))
                writeln('')
                stream.write(_bytes_)
            else:
                writeln('Content-Length: 0')
                writeln('')
        else:
            writeln('')

        # status code

        response_line = stream.readline()
        print('Received: %s' % response_line)
        line = response_line.decode('utf-8')
        match = status_code_regex.match(line)

        if match:

            status_code = int(match.group(1))
            print('Status Code: %s' % status_code)

        # parsing headers
        headers = {}
        while True:
            response_line = stream.readline()
            print('Received: %s' % response_line)
            if response_line:
                line = response_line.decode('utf-8')
            else:
                line = None

            if line == '\r\n' or not line:
                break

            match = header_regex.match(line)
            if match:
                key = match.group(1)
                value = match.group(2)

                value = value if value[-2:] != '\r\n' else value[:-2]

                headers[key] = value

        if line:
            try:
                length = int(headers['Content-Length'])
            except Exception as e:
                length = 0

            if length:
                data = stream.read(length)
            else:
                # assuming some small trivial data here
                data = stream.read(100)
            print('Received: %s' % data)
        stream.close()
        return (status_code, headers, data)


def urlparse(url):
    parts = url.split('/', 3)
    print(parts)
    proto = parts[0]
    # host, port = host.split(':') if ':' in host else (host, 80)
    host = parts[2]
    length = len(parts)
    if length == 4 and parts[3] == '':
        path = '/'
    elif length == 4 and parts[3] != '':
        path = '/' + parts[3]
    elif length == 3:
        path = '/'
    
    if ':' in host:
        host_parts = host.split(':') 
        port = int(host_parts[1])
        host = host_parts[0]
    else:
        if proto == 'http:':
            port = 80
        elif proto == 'https:':
            port = 443
        else:
            raise OSError('Unsupported protocol: %s' % proto[:-1])

    # if type(port) == str : port = int(port)
    return (proto,host, port, path)

def get(url):
    proto,host, port, path = urlparse(url)
    s = socket.socket()
    addr = socket.getaddressinfo(host, port)[0][-1]
    s.connect(addr)
    if proto == 'https:':
        assert SUPPORT_SSL, 'HTTPS not supported: could not find ussl'
        sock = ussl.wrap_socket(sock)

if __name__ == '__main__':
    print('Running test')
    client = HttpClient('http://micropython.org/ks/test.html')
    resp = client.do_request()
    print(resp)
